/*
 * REFREFFileDescriptorSet.cpp
 *
 *  Created on: May 12, 2013
 *      Author: Lucifer
 */
#include "../pch.h"

namespace BFX {

/**
 * Initializes a new instance of BFX::REFREFFileDescriptorSet.
 */
REFFileDescriptorSet::REFFileDescriptorSet()
{
#ifdef	_WIN32
	m_nCapacity = 1024;
	m_pFdSet = (VARIED_FD_SET*) new BYTE[sizeof(VARIED_FD_SET) - sizeof(SOCKET) + sizeof(SOCKET) * m_nCapacity];
#endif
	Reset();
}

/**
 * Destroys the BFX::REFREFFileDescriptorSet instance.
 */
REFFileDescriptorSet::~REFFileDescriptorSet()
{
#ifdef	_WIN32
	delete[] (BYTE*)m_pFdSet;
#endif
}

/**
 * Re-initializes the file descriptor set to contain no file descriptors.
 */
void REFFileDescriptorSet::Reset()
{
#ifdef	_WIN32
	m_pFdSet->fd_count = 0;
#else
	FD_ZERO(&m_fdSet);
#endif
	m_fdMax = INVALID_SOCKET;
}

/**
 * Adds a file descriptor to a file descriptor set.
 * @param The file descriptor.
 * @return True if the function successful; otherwise false.
 */
bool REFFileDescriptorSet::Set(SOCKET fd)
{
#ifdef	_WIN32
#define	MAX_SELECT	65536
	for (UINT i = 0; i < m_pFdSet->fd_count; i ++)
		if (m_pFdSet->fd_array[i] == fd)
			return true;

	if (m_pFdSet->fd_count >= MAX_SELECT)
		return false;

	if (m_pFdSet->fd_count == m_nCapacity)
	{
		UINT nCapacity = __MIN(m_nCapacity * 2, MAX_SELECT);
		VARIED_FD_SET* pNewFdSet = (VARIED_FD_SET*) new BYTE[sizeof(VARIED_FD_SET) - sizeof(SOCKET) + sizeof(SOCKET) * nCapacity];
		pNewFdSet->fd_count = m_pFdSet->fd_count;
		for (UINT i = 0; i < m_pFdSet->fd_count; i ++)
			pNewFdSet->fd_array[i] = m_pFdSet->fd_array[i];
		delete[] (BYTE*) m_pFdSet;
		m_pFdSet = pNewFdSet;
		m_nCapacity = nCapacity;
	}

	m_pFdSet->fd_array[m_pFdSet->fd_count++] = fd;
	return true;
#else
	if (fd < (SOCKET) FD_SETSIZE)
	{
		m_fdMax = __MAX(m_fdMax, fd);
		FD_SET(fd, &m_fdSet);
		return true;
	}
	return false;
#endif
}

/**
 * Gets a value indicates whether the file descriptor in the file descriptor set.
 * @param fd The file descriptor.
 * @return A value indicates whether the file descriptor in the file descriptor set.
 */
bool REFFileDescriptorSet::IsSet(SOCKET fd) const
{
#ifdef	_WIN32
	return (__WSAFDIsSet(fd, (fd_set*)m_pFdSet) != 0);
#else
	return (FD_ISSET(fd, &m_fdSet) != 0);
#endif
}

/**
 * Gets the pointer of the file descriptor set.
 */
REFFileDescriptorSet::operator fd_set*()
{
#ifdef	_WIN32
	return (fd_set*) m_pFdSet;
#else
	return &m_fdSet;
#endif
}

/**
 * Gets the max value of file descriptor in this file descriptor set.
 * @return
 */
SOCKET REFFileDescriptorSet::GetMaxFileDescriptor() const
{
	return m_fdMax;
}

} /* namespace BFX */
